#include "Barde.h"
#include <iostream>
using namespace std;

/*
  Une fois le Voleur OK, recopier ici les ajustements pour le Barde
 */

unsigned int Barde::comp_base[17] = {
  100, 100, 100, 20, 10, 50, 100, 100, 5, 100, 100, 100, 100, 100, 100, 100, 10
};

const unsigned int Barde::nbr_comp = 17;

const unsigned int Barde::nbr_restric = 0;

ListComp Barde::Comp[17] = {
  {"Amitié avec les animaux"           , 10, false},
  {"Barde en armure"                   , 10, false},
  {"Contre-chant"                      , 10, false},
  {"Détecter des bruits"               , 5 , true}, // base = 20%
  {"Détection de la magie"             , 10, true}, // base = 10%
  {"Grimper"                           , 5 , true}, // base = 50%
  {"Histoire"                          , 10, false},
  {"Inspiration"                       , 5 , false},
  {"Lire des langues inconnues"        , 5 , true}, // base = 5%
  {"Manipulation"                      , 5 , false},
  {"Résistance aux charmes"            , 5 , false},
  {"Résistance aux sons"               , 5 , false},
  {"Sorts de mage"                     , 10, false},
  {"Spécialisation"                    , 10, false},
  {"Utilisation de parchemins (niv 10)", 5 , false},
  {"Utilisation de parchemins"         , 10, false},
  {"Vol à la tire"                     , 10, true}  // base = 10%
};

Barde::Barde(unsigned int xp, unsigned int trait[7], unsigned int& PP)
  : Classe(xp, trait, Roublards)
{
  Type_classe = "Barde";
  PP += 70;
  dout(BLANK) << setfill('*') << setw(56) << '*' << setfill(' ') << endl;
  dout(BLANK) << "Création d'un barde" << endl << endl;
  unsigned int nbr(0);

  dout(BLANK) << "Tu as " << PP << " pp à dépenser" << endl;

  for (unsigned int i(0); i < nbr_comp; i++)
    dout(BLANK) << i+1 << ' ' << (Comp[i].Comp)
		<< " (" << Comp[i].Cout << " pp)" << endl;	
  dout(BLANK) << nbr_comp+1 << " Aucune" << endl;
  dout(BLANK) << "Choisir les compétences de classe" << endl;

  bool test(true), deja_pris, encore(false);
  unsigned int save_PP(PP);

  do
    {
      do
	{
	  nbr = demander_unsigned_borne("("+write_int(PP)+" restants) ", 1,
					nbr_comp + 1);
	  
	  if (nbr!=nbr_comp+1)
	    {
	      if (PP >= Comp[nbr-1].Cout)
		{
		  deja_pris = safe_push_back(&Comp_classe, nbr - 1);
		  if (deja_pris)	     
		    dout(WARN) << "Déjà sélectionné" << endl;
		  else
		    {
		      Comp_classe.push_back(nbr-1);
		      PP -= Comp[nbr-1].Cout;
		      dout(BLANK) << "Compétence choisie : "
				  << (Comp[nbr-1].Comp) << endl;
		      if (Comp[nbr-1].Pourcentage)
			{
			  Comp_classe.push_back(comp_base[nbr-1]);
			  dout(DEBUG) << nbr-1 << " => " << Comp[nbr-1].Comp
				      << " " << comp_base[nbr-1] << endl;
			}
		      else
			dout(DEBUG) << nbr-1 << " => " << Comp[nbr-1].Comp << endl;
		    }
		}
	      else
		dout(BLANK) << "Pas assez de pp" << endl;
	    }
	  else
	    test = false;
	}
      while(test);

      affiche_competences();
      dout(BLANK) << endl <<  "1 pour continuer, 2 pour recommencer" << endl;
      nbr = demander_unsigned_borne("Choix ", 1, 2);
      if (nbr == 2)
	{
	  PP = save_PP;
	  Comp_classe.clear();
	  test = true;
	  encore = true;
	  dout(BLANK) << endl;
	}
      else
	encore = false;
    }
  while(encore);


  for(unsigned int k(0); k < Comp_classe.size(); k++)
    dout(DEBUG) << Comp_classe[k] << ' ';
  dout(DEBUG) << endl;
  dout(BLANK) << endl << setfill('*') << setw(56) << '*' << setfill(' ')
	      << endl;
 calcul_niveau();
 calcul_niv_mag();

 augmenter_talents(20, false);
}

Barde::Barde(unsigned int xp, unsigned int trait[7])
  : Classe(xp, trait, Roublards)
{
  Type_classe = "Barde";
  calcul_niveau();
  calcul_niv_mag();
}

Barde::~Barde()
{}

void Barde::calcul_niveau()
{
  if (XP < 75000)
    {
      unsigned int i;
      for (i = 0; i < 5; i++)
	{
	  if (XP < (unsigned int) 1250 * puissance(2, i))
	    break;
	}
      Niveau = i + 1;
    }
  else if (XP < 70000)
    Niveau = 7;
  else if (XP < 110000)
    Niveau = 8;
  else if (XP < 160000)
    Niveau = 9;
  else if (XP < 220000)
    Niveau = 10;
  else
      Niveau = (XP - 220000) / 220000 + 11;
}

void Barde::afficher_stats()
{
  dout(BLANK) << "Barde" << endl;
  for (unsigned int i(0); i<6; i++)
    dout(BLANK) << Caracteristiques[i] << ' ' << Traits[i] << endl;
  for (unsigned int i(0); i<Comp_classe.size(); i++)
    {
      dout(DEBUG) << Comp_classe[i] << endl;
      if(Comp[Comp_classe[i]].Pourcentage)
	{
	  dout(BLANK) << (Comp[Comp_classe[i]].Comp)
		      << ' ' << Comp_classe[i+1] << '%' << endl;
	  i++;
	}
      else
	dout(BLANK) << (Comp[Comp_classe[i]].Comp)
		    << endl;
    }
}

void Barde::appliquer_modif(const string& type)
{
   if (type == "Nain")
    {
      comp_base[5]  -= 10;  // escalade
      comp_base[8]  -= 5;   // lire des langues inconnues
      comp_base[4]  += 5;   // détection de la magie
    }
  else if (type == "Elfe")
    {
      comp_base[16] += 5;   // vol à la tire
      comp_base[3]  += 5;   // détection des bruits
      comp_base[4]  += 10;  // détection de la magie
    }
  else if (type == "Gnome")
    {
      comp_base[3]  += 10;  // détection des bruits
      comp_base[5]  -= 15;  // escalade
      comp_base[4]  += 5;   // détection de la magie
    }
  else if (type == "Demi-Elfe")
    {
      comp_base[16] += 10;  // vol à la tire
      comp_base[4]  += 5;   // détection de la magie
    }
  else if (type == "Demi-Orque")
    {
      comp_base[3]  += 5;   // détection des bruits
    }
  else if (type == "Hobbit")
    {
      comp_base[16] += 5;   // vol à la tire
      comp_base[3]  += 10;  // détection des bruits
      comp_base[5]  -= 15;  // escalade
      comp_base[8]  -= 5;   // lire des langues inconnues
      comp_base[4]  += 5;   // détection de la magie
    }

  switch(Traits[1])
    {
    case 9:
      comp_base[16] -= 15;  // vol à la tire
      comp_base[5]  -= 10;  // escalade
      break;
    case 10:
      comp_base[16] -= 10;  // vol à la tire
      comp_base[5]  -= 5;   // escalade
      break;
    case 11:
      comp_base[16] -= 5;   // vol à la tire
      break;
    case 17:
      comp_base[16] += 5;   // vol à la tire
      comp_base[5]  += 5;   // escalade
      break;
    case 18:
      comp_base[16] += 10;  // vol à la tire
      comp_base[5]  += 10;  // escalade
      break;
    case 19:
      comp_base[16] += 15;  // vol à la tire
      comp_base[5]  += 15;  // escalade
      break;
    case 20:
      comp_base[16] += 20;  // vol à la tire
      comp_base[5]  += 20;  // escalade
      break;
    case 21:
      comp_base[16] += 20;  // vol à la tire
      comp_base[5]  += 20;  // escalade
      break;
    case 22:
      comp_base[16] += 25;  // vol à la tire
      comp_base[5]  += 25;  // escalade
      break;
    }

  unsigned int combien_comp(Comp_classe.size());
  vector<unsigned int> tmp;
  for (unsigned int i(0); i< combien_comp; i++)
    {     
      if (Comp[Comp_classe[i]].Pourcentage)
	{
	  tmp.push_back(Comp_classe[i]);
	  tmp.push_back(comp_base[Comp_classe[i]]);
	  i++;
	}
      else
       tmp.push_back(Comp_classe[i]);
    }
  Comp_classe.clear();
  for (unsigned int i(0); i< combien_comp; i++)
    Comp_classe.push_back(tmp[i]);
  for(unsigned int k(0); k < Comp_classe.size(); k++)
    dout(DEBUG) << Comp_classe[k] << ' ';
  dout(DEBUG) << endl;
}

void Barde::augmenter_talents(const unsigned int& bonus, const bool& lvl_up)
{
  vector<unsigned int> quelle, combien;
  unsigned int taille(get_combien()), nbr(0), depense, laquelle;
  
  for (unsigned int i(0); i<taille; i++)
    {
      dout(DEBUG) << Comp_classe[i];
      if (Comp[Comp_classe[i]].Pourcentage)
	{
	  dout(DEBUG) << " -> oui";
	  quelle.push_back(Comp_classe[i]);
	  combien.push_back(Comp_classe[i+1]);
	  i++;
	  nbr++;
	}
      dout(DEBUG) << endl;
    }

  unsigned int pps(bonus);
  dout(BLANK) << "Tu as " << pps << " point à dépenser dans les compétences";
  dout(BLANK) <<" suivantes:" << endl;
  for (unsigned int i(0); i<nbr; i++)
    {
      dout(DEBUG) << quelle[i] << " => " << Comp[quelle[i]].Comp << endl;
      dout(BLANK) << i+1 << " " << Comp[quelle[i]].Comp << " " << combien[i] 
		  << "%" << endl;
    }

  string poubelle;

  while(pps != 0)
    {
      
      laquelle =
	demander_unsigned_borne("Quelle compétence veux-tu améliorer? ",
				1, nbr);

      depense = demander_unsigned_borne("De combien? ", 0, pps);
      
      combien[laquelle-1] += depense;
      pps -= depense;
    }

  vector<unsigned int> tmp;
  unsigned int j(0);

  for (unsigned int i(0); i<taille; i++)
    {
      if (Comp[Comp_classe[i]].Pourcentage)
	{
	  tmp.push_back(Comp_classe[i]);
	  tmp.push_back(combien[j]);
	  j++;
	  i++;
	}
      else
	tmp.push_back(Comp_classe[i]);
    }
  Comp_classe.clear();
   for (unsigned int i(0); i<taille; i++)
     Comp_classe.push_back(tmp[i]);
  
}

void Barde::get_JS(unsigned int *tab) const
{
  *(tab + 0) = 13; // Paralysie, Poison ou Mort magique
  *(tab + 1) = 14; // Bâton, batonnet baguette
  *(tab + 2) = 12; // Pétrification ou Métamorphose
  *(tab + 3) = 16; // Souffles
  *(tab + 4) = 15; // Sorts
  
  unsigned int cat;
  if (Niveau <= 4)
    cat = 0;
  else  if (Niveau <= 8)
    cat = 1;
  else  if (Niveau <= 12)
    cat = 2;
  else  if (Niveau <= 16)
    cat = 3;
  else  if (Niveau <= 20)
    cat = 4;
  else
    cat = 5;

  *(tab + 0) -= cat;
  *(tab + 1) -= 2 * cat;
  *(tab + 2) -= cat;
  *(tab + 3) -= cat;
  *(tab + 4) -= 2 * cat;
}

string Barde::get_competence(const unsigned int& i) const
{
  if (Comp[get_comp(i)].Pourcentage)
    return " " + Comp[get_comp(i)].Comp + " " + write_int(get_comp(i+1)) + "\\%";
  else
    return Comp[get_comp(i)].Comp;
}

unsigned int Barde::calcule_TAc0() const
{
  unsigned int mod_niveau((Niveau - 1) / 2);

  return 20 - mod_niveau;
}

void Barde::calcul_niv_mag()
{
  bool a_des_sorts(false);
  for (unsigned int i(0); i < get_combien(); i++)
    {
      if (get_comp(i) == 7)
	{
	  a_des_sorts = true;
	  break;
	}
    }
  if (a_des_sorts)
    {
      if (Niveau < 4)
	Niveau_mag = (Niveau) / 2;
      else if (Niveau < 19)
	Niveau_mag = (Niveau + 2) / 3;
      else
	Niveau_mag = 6;  
    }
  else
    Niveau_mag = 0;
}

void Barde::ecrire_sorts(const string& nom_fichier, const bool& ecrase) const
{
  DebugLevelType etat_precedent(dout.getLevel());
  dout.setLevel(fonction);
  dout(FUNC) << "Barde::ecrire_sorts -> début" << endl;
  dout(DEBUG) << "Ne fait rien pour l'instant, à faire similaire au mage"
	      << endl;

  ofstream sortie;
  if (ecrase)
    {
      dout(DEBUG) << "Ecrasement du fichier " << nom_fichier << endl;
      sortie.open(nom_fichier.c_str());
    }
  else
    {
      sortie.open(nom_fichier.c_str(), ios::app);
      sortie << "\\newpage" << endl;
    }

  if (Niveau_mag == 0)
    return;

  sortie << "\\section*{Livre de sorts - Barde}" << endl;

  unsigned int *vec = new unsigned int[Niveau_mag];

  nbr_sort(vec, Niveau_mag);
  
  sortie << "\\begin{center}" << endl 
	 << "\\begin{tabular*}{10cm}{@{\\extracolsep{\\fill}} l r}"
	 << endl << "\\multicolumn{2}{c}{Nombre de sorts par jour} \\\\"
	 << "\\hline \\\\ \\vspace{1mm}" << endl;
  for (unsigned int i(0); i < Niveau_mag; i++)
    sortie << "Niveau " << i+1 << " & " << vec[i] << " \\\\" << endl;
  sortie << "\\end{tabular*}" << endl << "\\end{center}" << endl;

  bool ecoles[8] = {false, false, false, false, false, false, false, false};
  unsigned int taille(get_combien_sorts()), i, courant(10), niv_courant(10);
  string nom_ecoles[8] = {
    "Abjuration", "Alt\'eration", "Conjuration\\ -\\ Convocation", "Divination",
    "Enchantement\\ -\\ Charme", "Illusion", "Invocation\\ -\\ Evocation",
    "N\'ecromancie"};

  dout(DEBUG) << "nbr de sorts = " << taille << endl;

  for(i = 0; i < taille; i += 3)
    {
      if (Cl_sorts[i][0] != courant)
	{
	  courant = Cl_sorts[i][0];
	  sortie << "\\subsection*{" << affiche_accent(nom_ecoles[courant])
		 << "}" << endl;
	}
      if (Cl_sorts[i][1] != niv_courant)
	{
	  niv_courant = Cl_sorts[i][1];
	  sortie << "\\subsubsection*{Niveau " << niv_courant << "}" << endl;
	}

      sortie << "\\input{../../Sorts-mage/"
	     << supprime_accents(nom_ecoles[courant]) << "/sort_" << niv_courant
	     << "_" << Cl_sorts[i][2] << ".inc.tex}" << endl;
    }

  sortie.close();


  dout(FUNC) << "Barde::ecrire_sorts -> fin" << endl;
  dout.setLevel(etat_precedent);
}

void Barde::nbr_sort(unsigned int sorts[], const unsigned int& taille) const
{
  DebugLevelType etat_precedent(dout.getLevel());
  dout.setLevel(fonction);
  dout(FUNC) << "Barde::nbr_sort -> début" << endl;
  unsigned int i;
  unsigned int tmp[7];
  dout(FUNC) << "Taille = " << taille << endl;

  for (i = 0; i < taille; i++)
    tmp[i] = 0;

  switch(Niveau)
    {
    case 2:
      tmp[0] = 1;
      break;
    case 3:
      tmp[0] = 2;
      break;
    case 4:
      tmp[0] = 2;
      tmp[1] = 1;
      break;
    case 5:
      tmp[0] = 3;
      tmp[1] = 1;
      break;
    case 6:
      tmp[0] = 3;
      tmp[1] = 2;
      break;
    case 7:
      tmp[0] = 3;
      tmp[1] = 2;
      tmp[2] = 1;
      break;
    case 8:
      tmp[0] = 3;
      tmp[1] = 3;
      tmp[2] = 1;
      break;
    case 9:
      tmp[0] = 3;
      tmp[1] = 3;
      tmp[2] = 2;
      break;
    case 10:
      tmp[0] = 3;
      tmp[1] = 3;
      tmp[2] = 2;
      tmp[3] = 1;
      break;
    case 11:
      tmp[0] = 3;
      tmp[1] = 3;
      tmp[2] = 3;
      tmp[3] = 1;
      break;
    case 12:
      tmp[0] = 3;
      tmp[1] = 3;
      tmp[2] = 3;
      tmp[3] = 2;
      break;
    case 13:
      tmp[0] = 3;
      tmp[1] = 3;
      tmp[2] = 3;
      tmp[3] = 2;
      tmp[4] = 1;
      break;
    case 14:
      tmp[0] = 3;
      tmp[1] = 3;
      tmp[2] = 3;
      tmp[3] = 3;
      tmp[4] = 1;
      break;
    case 15:
      tmp[0] = 3;
      tmp[1] = 3;
      tmp[2] = 3;
      tmp[3] = 3;
      tmp[4] = 2;
      break;
    case 16:
      tmp[0] = 4;
      tmp[1] = 3;
      tmp[2] = 3;
      tmp[3] = 3;
      tmp[4] = 2;
      tmp[5] = 1;
      break;
    case 17:
      tmp[0] = 4;
      tmp[1] = 4;
      tmp[2] = 3;
      tmp[3] = 3;
      tmp[4] = 3;
      tmp[5] = 1;
      break;
    case 18:
      tmp[0] = 4;
      tmp[1] = 4;
      tmp[2] = 4;
      tmp[3] = 3;
      tmp[4] = 3;
      tmp[5] = 2;
      break;
    case 19:
      tmp[0] = 4;
      tmp[1] = 4;
      tmp[2] = 4;
      tmp[3] = 4;
      tmp[4] = 3;
      tmp[5] = 2;
      break;
    default:
      tmp[0] = 4;
      tmp[1] = 4;
      tmp[2] = 4;
      tmp[3] = 4;
      tmp[4] = 4;
      tmp[5] = 3;
      break;
    }

  for (i = 0; i < Niveau_mag; i++)
    sorts[i] = tmp[i];

  dout(FUNC) << "Barde::nbr_sort -> fin" << endl;
  dout.setLevel(etat_precedent);
}

/*****************************************************************************
 *
 * Permet de gérer l'ajout de sorts au livre du barde
 *
 * FUNC  permet d'afficher les messages de début - fin de la méthode
 * LFUNC permet d'afficher les écoles auxquelles le Mage a accès
 *
 *****************************************************************************/
void Barde::ajout_sorts()
{
  DebugLevelType etat_precedent(dout.getLevel());
  dout.setLevel(fonction);
  dout(FUNC) << "Barde::ajout_sorts -> début" << endl;
  
  unsigned int nbr, dernier, i;
  string ecole;

  if (Niveau_mag == 0)
    {
      dout(DEBUG) << "Niveau magique = 0" << endl;
      return;
    }
  for (i = 0; i < 8; i++)
    {
      for (unsigned int j(1); j <= Niveau_mag; j++)
	{
	  dout(BLANK) << "Niveau " << j << " :" << endl;
	  dernier = affiche_sorts(i, j);
	  
	  dout(DEBUG) << "dernier = " << dernier << endl;
	  
	  if (dernier > 0)
	    {
	      dout(BLANK) << setw(2) << dernier + 1 << " Aucun" << endl;
	      do
		{
		  nbr = demander_unsigned_borne("Entrer nouveau sort : ", 1,
						dernier + 1);
		  if (nbr != dernier + 1)
		    {
		      dout(DEBUG) << "Ajout du sort " << Sort(i, j, nbr - 1)
				      << endl;
		      Cl_sorts.push_back(Sort(i, j, nbr - 1));
		    }
		}
	      while(nbr != dernier + 1);
	    }
	}
    }
  
  vector<Sort>::iterator Begin, End, it;
  Begin = Cl_sorts.begin();
  End   = Cl_sorts.end();
  
  for (i = 0; i < Cl_sorts.size(); i++)
    dout(DEBUG) << Cl_sorts[i] << endl;
  
  dout(DEBUG) << "Tri effectué" << endl;
  
  sort(Begin, End);
  
  for (it = ++Begin; it != End; it++)
    {
      if (*it == *(it - 1))
	{
	  dout(LFUNC) << "Même sort!" << endl;
	  Cl_sorts.erase(it);	  
	}
    }
    
  
  for (i = 0; i < Cl_sorts.size(); i++)
    dout(DEBUG) << Cl_sorts[i] << endl;
  
  dout(FUNC) << "Barde::ajout_sorts -> fin" << endl;
  dout.setLevel(etat_precedent);
}
